﻿#include "UserObject.h"
#include "../Settings.h"
#include "../MirScenes/GameScene.h"
#include "../Forms/Client.CMain.h"
#include "../../Shared/Functions/Functions.h"
#include "../../Shared/Data/GuildData.h"
#include "../../Shared/Language.h"

using namespace Client::MirScenes;
namespace S = ServerPackets;

namespace Client::MirObjects
{

    UserObject::UserObject(unsigned int objectID) : PlayerObject(objectID)
    {
        Stats = new Stats();
    }

    void UserObject::Load(S::UserInformation *info)
    {
        Id = info->RealId;
        Name = info->Name;
        Settings::LoadTrackedQuests(info->Name);
        NameColour = info->NameColour;
        GuildName = info->GuildName;
        GuildRankName = info->GuildRank;
        Class = info->Class;
        Gender = info->Gender;
        Level = info->Level;

        CurrentLocation = info->Location;
        MapLocation = info->Location;
        GameScene::Scene->MapControl->AddObject(this);

        Direction = info->Direction;
        Hair = info->Hair;

        HP = info->HP;
        MP = info->MP;

        Experience = info->Experience;
        MaxExperience = info->MaxExperience;

        LevelEffects = info->LevelEffects;

        Inventory = info->Inventory;
        Equipment = info->Equipment;
        QuestInventory = info->QuestInventory;

        HasExpandedStorage = info->HasExpandedStorage;
        ExpandedStorageExpiryTime = info->ExpandedStorageExpiryTime;

        Magics = info->Magics;
        for (int i = 0; i < Magics.size(); i++)
        {
            if (Magics[i]->CastTime > 0)
            {
                Magics[i]->CastTime = CMain::Time - Magics[i]->CastTime;
            }
        }

        IntelligentCreatures = info->IntelligentCreatures; //IntelligentCreature
        SummonedCreatureType = info->SummonedCreatureType; //IntelligentCreature
        CreatureSummoned = info->CreatureSummoned; //IntelligentCreature

        BindAllItems();

        RefreshStats();

        SetAction();
    }

    void UserObject::SetSlots(S::UserSlotsRefresh *p)
    {
        Inventory = p->Inventory;
        Equipment = p->Equipment;

        BindAllItems();
        RefreshStats();
    }

    void UserObject::SetLibraries()
    {
        PlayerObject::SetLibraries();
    }

    void UserObject::SetEffects()
    {
        PlayerObject::SetEffects();
    }

    void UserObject::RefreshStats()
    {
        Stats->Clear();

        RefreshLevelStats();
        RefreshBagWeight();
        RefreshEquipmentStats();
        RefreshItemSetStats();
        RefreshMirSetStats();
        RefreshSkills();
        RefreshBuffs();
        RefreshGuildBuffs();

        SetLibraries();
        SetEffects();

        Stats[Stat::HP] += (Stats[Stat::HP] * Stats[Stat::HPRatePercent]) / 100;
        Stats[Stat::MP] += (Stats[Stat::MP] * Stats[Stat::MPRatePercent]) / 100;
        Stats[Stat::MaxAC] += (Stats[Stat::MaxAC] * Stats[Stat::MaxACRatePercent]) / 100;
        Stats[Stat::MaxMAC] += (Stats[Stat::MaxMAC] * Stats[Stat::MaxMACRatePercent]) / 100;

        Stats[Stat::MaxDC] += (Stats[Stat::MaxDC] * Stats[Stat::MaxDCRatePercent]) / 100;
        Stats[Stat::MaxMC] += (Stats[Stat::MaxMC] * Stats[Stat::MaxMCRatePercent]) / 100;
        Stats[Stat::MaxSC] += (Stats[Stat::MaxSC] * Stats[Stat::MaxSCRatePercent]) / 100;
        Stats[Stat::AttackSpeed] += (Stats[Stat::AttackSpeed] * Stats[Stat::AttackSpeedRatePercent]) / 100;

        RefreshStatCaps();

        if (this == User && Light < 3)
        {
            Light = 3;
        }
        AttackSpeed = 1400 - ((Stats[Stat::AttackSpeed] * 60) + std::min(370, (Level * 14)));
        if (AttackSpeed < 550)
        {
            AttackSpeed = 550;
        }

        PercentHealth = static_cast<unsigned char>(HP / static_cast<float>(Stats[Stat::HP]) * 100);

        GameScene::Scene->Redraw();
    }

    void UserObject::RefreshLevelStats()
    {
        Light = 0;

        for (auto stat : *CoreStats->Stats)
        {
            Stats[stat->Type] = stat->Calculate(Class, Level);
        }
    }

    void UserObject::RefreshBagWeight()
    {
        CurrentBagWeight = 0;

        for (int i = 0; i < Inventory.size(); i++)
        {
            UserItem *item = Inventory[i];
            if (item != nullptr)
            {
                CurrentBagWeight += item->getWeight();
            }
        }
    }

    void UserObject::RefreshEquipmentStats()
    {
        Weapon = -1;
        WeaponEffect = 0;
        Armour = 0;
        WingEffect = 0;
        MountType = -1;

        CurrentWearWeight = 0;
        CurrentHandWeight = 0;

        ItemMode = SpecialItemMode::None;
        FastRun = false;

        ItemSets.clear();
        MirSet.clear();

        for (int i = 0; i < Equipment.size(); i++)
        {
            UserItem *temp = Equipment[i];
            if (temp == nullptr)
            {
                continue;
            }

            ItemInfo *RealItem = Functions::GetRealItem(temp->Info, Level, Class, GameScene::ItemInfoList);

            if (RealItem->Type == ItemType::Weapon || RealItem->Type == ItemType::Torch)
            {
                CurrentHandWeight = static_cast<int>(std::min(std::numeric_limits<int>::max(), CurrentHandWeight + temp->getWeight()));
            }
            else
            {
                CurrentWearWeight = static_cast<int>(std::min(std::numeric_limits<int>::max(), CurrentWearWeight + temp->getWeight()));
            }

            if (temp->CurrentDura == 0 && RealItem->Durability > 0)
            {
                continue;
            }

            Stats->Add(RealItem->Stats);
            Stats->Add(temp->AddedStats);

            Stats[Stat::MinAC] += temp->Awake->GetAC();
            Stats[Stat::MaxAC] += temp->Awake->GetAC();
            Stats[Stat::MinMAC] += temp->Awake->GetMAC();
            Stats[Stat::MaxMAC] += temp->Awake->GetMAC();

            Stats[Stat::MinDC] += temp->Awake->GetDC();
            Stats[Stat::MaxDC] += temp->Awake->GetDC();
            Stats[Stat::MinMC] += temp->Awake->GetMC();
            Stats[Stat::MaxMC] += temp->Awake->GetMC();
            Stats[Stat::MinSC] += temp->Awake->GetSC();
            Stats[Stat::MaxSC] += temp->Awake->GetSC();

            Stats[Stat::HP] += temp->Awake->GetHPMP();
            Stats[Stat::MP] += temp->Awake->GetHPMP();

            if (RealItem->Light > Light)
            {
                Light = RealItem->Light;
            }
            if (RealItem->Unique != SpecialItemMode::None)
            {
                ItemMode |= RealItem->Unique;
            }

            if (RealItem->CanFastRun)
            {
                FastRun = true;
            }

            RefreshSocketStats(temp);

            if (RealItem->Type == ItemType::Armour)
            {
                Armour = RealItem->Shape;
                WingEffect = RealItem->Effect;
            }
            if (RealItem->Type == ItemType::Weapon)
            {
                Weapon = RealItem->Shape;
                WeaponEffect = RealItem->Effect;
            }

            if (RealItem->Type == ItemType::Mount)
            {
                MountType = RealItem->Shape;
            }

            if (RealItem->Set == ItemSet::None)
            {
                continue;
            }

            ItemSets *itemSet = ItemSets.Where([&] (std::any set)
            {
                return set->Set == RealItem->Set && !set::Type->Contains(RealItem->Type) && !set::SetComplete;
            }).FirstOrDefault();

            if (itemSet != nullptr)
            {
                itemSet->Type.push_back(RealItem->Type);
                itemSet->Count++;
            }
            else
            {
                ItemSets *tempVar = new ItemSets();
                tempVar->Count = 1;
                tempVar->Set = RealItem->Set;
                tempVar->Type = {RealItem->Type};
                ItemSets.push_back(tempVar);

//C# TO C++ CONVERTER TODO TASK: A 'delete tempVar' statement was not added since tempVar was passed to a method or constructor. Handle memory management manually.
            }

            //Mir Set
            if (RealItem->Set == ItemSet::Mir)
            {
                if (!std::find(MirSet.begin(), MirSet.end(), static_cast<EquipmentSlot>(i) != MirSet.end()))
                {
                    MirSet.push_back(static_cast<EquipmentSlot>(i));
                }
            }
        }

        if (ItemMode::HasFlag(SpecialItemMode::Muscle))
        {
            Stats[Stat::BagWeight] = Stats[Stat::BagWeight] * 2;
            Stats[Stat::WearWeight] = Stats[Stat::WearWeight] * 2;
            Stats[Stat::HandWeight] = Stats[Stat::HandWeight] * 2;
        }
    }

    void UserObject::RefreshSocketStats(UserItem *equipItem)
    {
        if (equipItem == nullptr)
        {
            return;
        }

        if (equipItem->Info->Type == ItemType::Weapon && equipItem->Info->isFishingRod())
        {
            return;
        }

        if (equipItem->Info->Type == ItemType::Mount && !RidingMount)
        {
            return;
        }

        for (int i = 0; i < equipItem->Slots.size(); i++)
        {
            UserItem *temp = equipItem->Slots[i];

            if (temp == nullptr)
            {
                continue;
            }
            ItemInfo *RealItem = Functions::GetRealItem(temp->Info, Level, Class, GameScene::ItemInfoList);

            if (RealItem->Type == ItemType::Weapon || RealItem->Type == ItemType::Torch)
            {
                CurrentHandWeight = static_cast<int>(std::min(std::numeric_limits<int>::max(), CurrentHandWeight + temp->getWeight()));
            }
            else
            {
                CurrentWearWeight = static_cast<int>(std::min(std::numeric_limits<int>::max(), CurrentWearWeight + temp->getWeight()));
            }

            if (temp->CurrentDura == 0 && RealItem->Durability > 0)
            {
                continue;
            }

            Stats->Add(RealItem->Stats);
            Stats->Add(temp->AddedStats);

            if (RealItem->Light > Light)
            {
                Light = RealItem->Light;
            }
            if (RealItem->Unique != SpecialItemMode::None)
            {
                ItemMode |= RealItem->Unique;
            }
        }
    }

    void UserObject::RefreshItemSetStats()
    {
        for (auto s : ItemSets)
        {
            if ((s->Set == ItemSet::Smash) && ((std::find(s->Type.begin(), s->Type.end(), ItemType::Ring) != s->Type.end() && s->Type.Contains(ItemType::Bracelet)) || (s->Type.Contains(ItemType::Ring) && s->Type.Contains(ItemType::Necklace)) || (s->Type.Contains(ItemType::Bracelet) && s->Type.Contains(ItemType::Necklace))))
            {
                Stats[Stat::AttackSpeed] += 2;
            }

            if ((s->Set == ItemSet::Purity) && (std::find(s->Type.begin(), s->Type.end(), ItemType::Ring) != s->Type.end()) && (s->Type.Contains(ItemType::Bracelet)))
            {
                Stats[Stat::Holy] += 3;
            }

            if ((s->Set == ItemSet::HwanDevil) && (std::find(s->Type.begin(), s->Type.end(), ItemType::Ring) != s->Type.end()) && (s->Type.Contains(ItemType::Bracelet)))
            {
                Stats[Stat::WearWeight] += 5;
                Stats[Stat::BagWeight] += 20;
            }

            if ((s->Set == ItemSet::DarkGhost) && (std::find(s->Type.begin(), s->Type.end(), ItemType::Necklace) != s->Type.end()) && (s->Type.Contains(ItemType::Bracelet)))
            {
                Stats[Stat::HP] += 25;
            }

            if (!s->getSetComplete())
            {
                continue;
            }

            switch (s->Set)
            {
                case ItemSet::Mundane:
                    Stats[Stat::HP] += 50;
                    break;
                case ItemSet::NokChi:
                    Stats[Stat::MP] += 50;
                    break;
                case ItemSet::TaoProtect:
                    Stats[Stat::HP] += 30;
                    Stats[Stat::MP] += 30;
                    break;
                case ItemSet::RedOrchid:
                    Stats[Stat::Accuracy] += 2;
                    Stats[Stat::HPDrainRatePercent] += 10;
                    break;
                case ItemSet::RedFlower:
                    Stats[Stat::HP] += 50;
                    Stats[Stat::MP] -= 25;
                    break;
                case ItemSet::Smash:
                    Stats[Stat::MinDC] += 1;
                    Stats[Stat::MaxDC] += 3;
                    break;
                case ItemSet::HwanDevil:
                    Stats[Stat::MinMC] += 1;
                    Stats[Stat::MaxMC] += 2;
                    break;
                case ItemSet::Purity:
                    Stats[Stat::MinSC] += 1;
                    Stats[Stat::MaxSC] += 2;
                    break;
                case ItemSet::FiveString:
                    Stats[Stat::HP] += static_cast<int>((static_cast<double>(Stats[Stat::HP]) / 100) * 30);
                    Stats[Stat::MinAC] += 2;
                    Stats[Stat::MaxAC] += 2;
                    break;
                case ItemSet::Spirit:
                    Stats[Stat::MinDC] += 2;
                    Stats[Stat::MaxDC] += 5;
                    Stats[Stat::AttackSpeed] += 2;
                    break;
                case ItemSet::Bone:
                    Stats[Stat::MaxAC] += 2;
                    Stats[Stat::MaxMC] += 1;
                    Stats[Stat::MaxSC] += 1;
                    break;
                case ItemSet::Bug:
                    Stats[Stat::MaxDC] += 1;
                    Stats[Stat::MaxMC] += 1;
                    Stats[Stat::MaxSC] += 1;
                    Stats[Stat::MaxMAC] += 1;
                    Stats[Stat::PoisonResist] += 1;
                    break;
                case ItemSet::WhiteGold:
                    Stats[Stat::MaxDC] += 2;
                    Stats[Stat::MaxAC] += 2;
                    break;
                case ItemSet::WhiteGoldH:
                    Stats[Stat::MaxDC] += 3;
                    Stats[Stat::HP] += 30;
                    Stats[Stat::AttackSpeed] += 2;
                    break;
                case ItemSet::RedJade:
                    Stats[Stat::MaxMC] += 2;
                    Stats[Stat::MaxMAC] += 2;
                    break;
                case ItemSet::RedJadeH:
                    Stats[Stat::MaxMC] += 2;
                    Stats[Stat::MP] += 40;
                    Stats[Stat::Agility] += 2;
                    break;
                case ItemSet::Nephrite:
                    Stats[Stat::MaxSC] += 2;
                    Stats[Stat::MaxAC] += 1;
                    Stats[Stat::MaxMAC] += 1;
                    break;
                case ItemSet::NephriteH:
                    Stats[Stat::MaxSC] += 2;
                    Stats[Stat::HP] += 15;
                    Stats[Stat::MP] += 20;
                    Stats[Stat::Holy] += 1;
                    Stats[Stat::Accuracy] += 1;
                    break;
                case ItemSet::Whisker1:
                    Stats[Stat::MaxDC] += 1;
                    Stats[Stat::BagWeight] += 25;
                    break;
                case ItemSet::Whisker2:
                    Stats[Stat::MaxMC] += 1;
                    Stats[Stat::BagWeight] += 17;
                    break;
                case ItemSet::Whisker3:
                    Stats[Stat::MaxSC] += 1;
                    Stats[Stat::BagWeight] += 17;
                    break;
                case ItemSet::Whisker4:
                    Stats[Stat::MaxDC] += 1;
                    Stats[Stat::BagWeight] += 20;
                    break;
                case ItemSet::Whisker5:
                    Stats[Stat::MaxDC] += 1;
                    Stats[Stat::BagWeight] += 17;
                    break;
                case ItemSet::Hyeolryong:
                    Stats[Stat::MaxSC] += 2;
                    Stats[Stat::HP] += 15;
                    Stats[Stat::MP] += 20;
                    Stats[Stat::Holy] += 1;
                    Stats[Stat::Accuracy] += 1;
                    break;
                case ItemSet::Monitor:
                    Stats[Stat::MagicResist] += 1;
                    Stats[Stat::PoisonResist] += 1;
                    break;
                case ItemSet::Oppressive:
                    Stats[Stat::MaxAC] += 1;
                    Stats[Stat::Agility] += 1;
                    break;
                case ItemSet::BlueFrost:
                    Stats[Stat::MinDC] += 1;
                    Stats[Stat::MaxDC] += 1;
                    Stats[Stat::MinMC] += 1;
                    Stats[Stat::MaxMC] += 1;
                    Stats[Stat::HandWeight] += 1;
                    Stats[Stat::WearWeight] += 2;
                    break;
                case ItemSet::BlueFrostH:
                    Stats[Stat::MinDC] += 1;
                    Stats[Stat::MaxDC] += 2;
                    Stats[Stat::MaxMC] += 2;
                    Stats[Stat::Accuracy] += 1;
                    Stats[Stat::HP] += 50;
                    break;
                case ItemSet::DarkGhost:
                    Stats[Stat::MP] += 25;
                    Stats[Stat::AttackSpeed] += 2;
                    break;
            }
        }
    }

    void UserObject::RefreshMirSetStats()
    {
        if (MirSet.size()() == 10)
        {
            Stats[Stat::MaxAC] += 1;
            Stats[Stat::MaxMAC] += 1;
            Stats[Stat::BagWeight] += 70;
            Stats[Stat::Luck] += 2;
            Stats[Stat::AttackSpeed] += 2;
            Stats[Stat::HP] += 70;
            Stats[Stat::MP] += 80;
            Stats[Stat::MagicResist] += 6;
            Stats[Stat::PoisonResist] += 6;
        }

        if (std::find(MirSet.begin(), MirSet.end(), EquipmentSlot::RingL) != MirSet.end() && MirSet.Contains(EquipmentSlot::RingR))
        {
            Stats[Stat::MaxMAC] += 1;
            Stats[Stat::MaxAC] += 1;
        }
        if (std::find(MirSet.begin(), MirSet.end(), EquipmentSlot::BraceletL) != MirSet.end() && MirSet.Contains(EquipmentSlot::BraceletR))
        {
            Stats[Stat::MinAC] += 1;
            Stats[Stat::MinMAC] += 1;
        }
        if ((std::find(MirSet.begin(), MirSet.end(), EquipmentSlot::RingL) != MirSet.end() | MirSet.Contains(EquipmentSlot::RingR)) && (MirSet.Contains(EquipmentSlot::BraceletL) | MirSet.Contains(EquipmentSlot::BraceletR)) && MirSet.Contains(EquipmentSlot::Necklace))
        {
            Stats[Stat::MaxMAC] += 1;
            Stats[Stat::MaxAC] += 1;
            Stats[Stat::BagWeight] += 30;
            Stats[Stat::WearWeight] += 17;
        }
        if (std::find(MirSet.begin(), MirSet.end(), EquipmentSlot::RingL) != MirSet.end() && MirSet.Contains(EquipmentSlot::RingR) && MirSet.Contains(EquipmentSlot::BraceletL) && MirSet.Contains(EquipmentSlot::BraceletR) && MirSet.Contains(EquipmentSlot::Necklace))
        {
            Stats[Stat::MaxMAC] += 1;
            Stats[Stat::MaxAC] += 1;
            Stats[Stat::BagWeight] += 20;
            Stats[Stat::WearWeight] += 10;
        }
        if (std::find(MirSet.begin(), MirSet.end(), EquipmentSlot::Armour) != MirSet.end() && MirSet.Contains(EquipmentSlot::Helmet) && MirSet.Contains(EquipmentSlot::Weapon))
        {
            Stats[Stat::MaxDC] += 2;
            Stats[Stat::MaxMC] += 1;
            Stats[Stat::MaxSC] += 1;
            Stats[Stat::Agility] += 1;
        }
        if (std::find(MirSet.begin(), MirSet.end(), EquipmentSlot::Armour) != MirSet.end() && MirSet.Contains(EquipmentSlot::Boots) && MirSet.Contains(EquipmentSlot::Belt))
        {
            Stats[Stat::MaxDC] += 1;
            Stats[Stat::MaxMC] += 1;
            Stats[Stat::MaxSC] += 1;
            Stats[Stat::HandWeight] += 17;
        }
        if (std::find(MirSet.begin(), MirSet.end(), EquipmentSlot::Armour) != MirSet.end() && MirSet.Contains(EquipmentSlot::Boots) && MirSet.Contains(EquipmentSlot::Belt) && MirSet.Contains(EquipmentSlot::Helmet) && MirSet.Contains(EquipmentSlot::Weapon))
        {
            Stats[Stat::MinDC] += 1;
            Stats[Stat::MaxDC] += 1;
            Stats[Stat::MinMC] += 1;
            Stats[Stat::MaxMC] += 1;
            Stats[Stat::MinSC] += 1;
            Stats[Stat::MaxSC] += 1;
            Stats[Stat::HandWeight] += 17;
        }
    }

    void UserObject::RefreshSkills()
    {
        for (int i = 0; i < Magics.size(); i++)
        {
            ClientMagic *magic = Magics[i];
            switch (magic->Spell)
            {
                case Spell::Fencing:
                    Stats[Stat::Accuracy] += magic->Level * 3;
                    Stats[Stat::MaxAC] += (magic->Level + 1) * 3;
                    break;
                case Spell::FatalSword:
                    Stats[Stat::Accuracy] += magic->Level;
                    break;
                case Spell::SpiritSword:
                    Stats[Stat::Accuracy] += magic->Level;
                    Stats[Stat::MaxDC] += static_cast<int>(Stats[Stat::MaxSC] * (magic->Level + 1) * 0.1F);
                    break;
            }
        }
    }

    void UserObject::RefreshBuffs()
    {
        TransformType = -1;

        for (int i = 0; i < GameScene::Scene->Buffs.size(); i++)
        {
            ClientBuff *buff = GameScene::Scene->Buffs[i];

            Stats->Add(buff->Stats);

            switch (buff->Type)
            {
                case BuffType::SwiftFeet:
                    Sprint = true;
                    break;
                case BuffType::Transform:
                    TransformType = static_cast<short>(buff->Values[0]);
                    break;
            }

        }
    }

    void UserObject::RefreshGuildBuffs()
    {
        if (User != this)
        {
            return;
        }
        if (GameScene::Scene->GuildDialog == nullptr)
        {
            return;
        }
        for (int i = 0; i < GameScene::Scene->GuildDialog->EnabledBuffs.size(); i++)
        {
            GuildBuff *buff = GameScene::Scene->GuildDialog->EnabledBuffs[i];
            if (buff == nullptr)
            {
                continue;
            }
            if (!buff->Active)
            {
                continue;
            }

            if (buff->Info == nullptr)
            {
                buff->Info = GameScene::Scene->GuildDialog->FindGuildBuffInfo(buff->Id);
            }

            if (buff->Info == nullptr)
            {
                continue;
            }

            Stats->Add(buff->Info->Stats);
        }
    }

    void UserObject::RefreshStatCaps()
    {
        for (auto cap : *CoreStats->Caps)
        {
            Stats[cap->second.Key] = std::min(cap->second->Value, Stats[cap->second.Key]);
        }

        Stats[Stat::HP] = std::max(0, Stats[Stat::HP]);
        Stats[Stat::MP] = std::max(0, Stats[Stat::MP]);

        Stats[Stat::MinAC] = std::max(0, Stats[Stat::MinAC]);
        Stats[Stat::MaxAC] = std::max(0, Stats[Stat::MaxAC]);
        Stats[Stat::MinMAC] = std::max(0, Stats[Stat::MinMAC]);
        Stats[Stat::MaxMAC] = std::max(0, Stats[Stat::MaxMAC]);
        Stats[Stat::MinDC] = std::max(0, Stats[Stat::MinDC]);
        Stats[Stat::MaxDC] = std::max(0, Stats[Stat::MaxDC]);
        Stats[Stat::MinMC] = std::max(0, Stats[Stat::MinMC]);
        Stats[Stat::MaxMC] = std::max(0, Stats[Stat::MaxMC]);
        Stats[Stat::MinSC] = std::max(0, Stats[Stat::MinSC]);
        Stats[Stat::MaxSC] = std::max(0, Stats[Stat::MaxSC]);

        Stats[Stat::MinDC] = std::min(Stats[Stat::MinDC], Stats[Stat::MaxDC]);
        Stats[Stat::MinMC] = std::min(Stats[Stat::MinMC], Stats[Stat::MaxMC]);
        Stats[Stat::MinSC] = std::min(Stats[Stat::MinSC], Stats[Stat::MaxSC]);
    }

    void UserObject::BindAllItems()
    {
        for (int i = 0; i < Inventory.size(); i++)
        {
            if (Inventory[i] == nullptr)
            {
                continue;
            }
            GameScene::Bind(Inventory[i]);
        }

        for (int i = 0; i < Equipment.size(); i++)
        {
            if (Equipment[i] == nullptr)
            {
                continue;
            }
            GameScene::Bind(Equipment[i]);
        }

        for (int i = 0; i < QuestInventory.size(); i++)
        {
            if (QuestInventory[i] == nullptr)
            {
                continue;
            }
            GameScene::Bind(QuestInventory[i]);
        }
    }

    ClientMagic *UserObject::GetMagic(Spell spell)
    {
        for (int i = 0; i < Magics.size(); i++)
        {
            ClientMagic *magic = Magics[i];
            if (magic->Spell != spell)
            {
                continue;
            }
            return magic;
        }

        return nullptr;
    }

    void UserObject::GetMaxGain(UserItem *item)
    {
        if (CurrentBagWeight + item->getWeight() <= Stats[Stat::BagWeight] && FreeSpace(Inventory) > 0)
        {
            return;
        }

        unsigned short min = 0;
        unsigned short max = item->Count;

        if (CurrentBagWeight >= Stats[Stat::BagWeight])
        {

        }

        if (item->Info->Type == ItemType::Amulet)
        {
            for (int i = 0; i < Inventory.size(); i++)
            {
                UserItem *bagItem = Inventory[i];

                if (bagItem == nullptr || bagItem->Info != item->Info)
                {
                    continue;
                }

                if (bagItem->Count + item->Count <= bagItem->Info->StackSize)
                {
                    item->Count = max;
                    return;
                }
                item->Count = static_cast<unsigned short>(bagItem->Info->StackSize - bagItem->Count);
                min += item->Count;
                if (min >= max)
                {
                    item->Count = max;
                    return;
                }
            }

            if (min == 0)
            {
                GameScene::Scene->ChatDialog->ReceiveChat(FreeSpace(Inventory) == 0 ? GameLanguage::NoBagSpace : "You do not have enough weight.", ChatType::System);

                item->Count = 0;
                return;
            }

            item->Count = min;
            return;
        }

        if (CurrentBagWeight + item->getWeight() > Stats[Stat::BagWeight])
        {
            item->Count = static_cast<unsigned short>(std::max((Stats[Stat::BagWeight] - CurrentBagWeight), std::numeric_limits<unsigned short>::min()) / item->Info->Weight);
            max = item->Count;
            if (item->Count == 0)
            {
                GameScene::Scene->ChatDialog->ReceiveChat("You do not have enough weight.", ChatType::System);
                return;
            }
        }

        if (item->Info->StackSize > 1)
        {
            for (int i = 0; i < Inventory.size(); i++)
            {
                UserItem *bagItem = Inventory[i];

                if (bagItem == nullptr)
                {
                    return;
                }
                if (bagItem->Info != item->Info)
                {
                    continue;
                }

                if (bagItem->Count + item->Count <= bagItem->Info->StackSize)
                {
                    item->Count = max;
                    return;
                }

                item->Count = static_cast<unsigned short>(bagItem->Info->StackSize - bagItem->Count);
                min += item->Count;
                if (min >= max)
                {
                    item->Count = max;
                    return;
                }
            }

            if (min == 0)
            {
                GameScene::Scene->ChatDialog->ReceiveChat(GameLanguage::NoBagSpace, ChatType::System);
                item->Count = 0;
            }
        }
        else
        {
            GameScene::Scene->ChatDialog->ReceiveChat(GameLanguage::NoBagSpace, ChatType::System);
            item->Count = 0;
        }

    }

    int UserObject::FreeSpace(std::vector<UserItem*> &array)
    {
        int count = 0;
        for (int i = 0; i < array.size(); i++)
        {
            count++;
        }
        return count;
    }

    void UserObject::SetAction()
    {
        if (QueuedAction != nullptr)
        {
            if ((ActionFeed.empty()) || (ActionFeed.size() == 1 && getNextAction()->Action == MirAction::Stance))
            {
                ActionFeed.clear();
                ActionFeed.push_back(QueuedAction);
                QueuedAction = nullptr;
            }
        }

        PlayerObject::SetAction();
    }

    void UserObject::ProcessFrames()
    {
        bool clear = CMain::Time >= NextMotion;

        PlayerObject::ProcessFrames();

        if (clear)
        {
            QueuedAction = nullptr;
        }
        if ((CurrentAction == MirAction::Standing || CurrentAction == MirAction::MountStanding || CurrentAction == MirAction::Stance || CurrentAction == MirAction::Stance2 || CurrentAction == MirAction::DashFail) && (QueuedAction != nullptr || getNextAction() != nullptr))
        {
            SetAction();
        }
    }

    void UserObject::ClearMagic()
    {
        NextMagic = nullptr;
        NextMagicDirection = (MirDirection)0;
        NextMagicLocation = Point::Empty;
        NextMagicObject = nullptr;
    }
}
